#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <gmp.h>
#include <pthread.h>

#define THREADS_MAX 4

//variaveis globais
pthread_mutex_t mutex= PTHREAD_MUTEX_INITIALIZER; //para acessar a variavel pontos que e uma regiao critica
int amostra = 100000; // tamanho da amostra
int pontos = 0; // quantidade de pontos que estao dentro de 1/4 da circunferencia

void *MonteCarloParalelo(void *arguments);

int main(int argc, char *argv[]){

     pthread_t nro_threads[THREADS_MAX];
     int i;
     double pi;
    
     for(i=0; i< THREADS_MAX; i++)
     pthread_create(&nro_threads[i],NULL,MonteCarloParalelo,NULL);

     for(i=0; i< THREADS_MAX; i++)
     pthread_join(nro_threads[i],NULL);


     pi = (4* (double)pontos) / (double)amostra;

     printf("\nPi = %g \n",pi);
     
     return 0;

}

void *MonteCarloParalelo(void *arguments){

     int i,aux4,pontos_func =0; 
     mpf_t x,y,random,aux1, aux2,aux3,raio;
	
     //definindo a precisao
     mpf_set_default_prec(100000);

     mpf_init(x);
     mpf_init(y);
     mpf_init(random);
     mpf_init(aux1);
     mpf_init(aux2);
     mpf_init(aux3);
     mpf_init(raio);
     
     srand (time(NULL));

     for(i=0;i< (amostra/THREADS_MAX); i++){ // amostra/THREADS_MAX define o numero de iteracoes que cada thread faz
                
		// gera valor de x
		mpf_init_set_d(random,rand());
		mpf_div_ui(x,random,RAND_MAX);
		
		// gera valor de y
		mpf_init_set_d(random,rand());
		mpf_div_ui(y,random,RAND_MAX);

		//calculando a distancia
		mpf_mul(aux1,x,x);
    		mpf_mul(aux2,y,y);
		mpf_add(aux3,aux1,aux2);
    		mpf_sqrt(raio,aux3);

		aux4 = mpf_cmp_ui(raio, 1);
                if(aux4 <= 0){  
                      pontos_func++;
                      
                }

      }

      mpf_clear(x);
      mpf_clear(y);
      mpf_clear(random);
      mpf_clear(aux1);
      mpf_clear(aux2);
      mpf_clear(aux3);
      mpf_clear(raio);
      
      // garantindo exclusao mutua na regiao critica
      pthread_mutex_lock(&mutex);
       pontos += pontos_func;
      pthread_mutex_unlock(&mutex);	

      pthread_exit(NULL);

}
